package com.finance.expensrem;

import java.util.Iterator;
import java.util.Stack;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.GridView;
import android.widget.TextView;

public class CalculatorActivity extends Activity {
	
	GridView mKeyGrid;
	KeypadAdapter mKeypadAdapter;
	TextView userInputText;
	
	Stack <String> mInputStack;
	Stack <String> mOperationStack;
	
	boolean pointInput = true;
	boolean resetInput = false;
	boolean hasFinalResult = false;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_calculator);
        
        // Get reference to the key GridView
        mKeyGrid = (GridView) findViewById(R.id.gridViewButtons);
        
        // Get reference to the user input TextView
        userInputText = (TextView) findViewById(R.id.txtInput);
        userInputText.setText("0");
        
        // Create the stack
        mInputStack = new Stack <String> ();
        mOperationStack = new Stack <String> ();
        
        // Create Keypad Adapter
        mKeypadAdapter = new KeypadAdapter(this);
        
        // Set adapter of the keypad grid
        mKeyGrid.setAdapter(mKeypadAdapter);
        
        // Set button click listener of the keypad adapter
        mKeypadAdapter.setOnButtonClickListener(new OnClickListener() {
	        @Override
	        public void onClick(View v) {
	          Button btn = (Button) v;
	          // Get the KeypadButton value which is used to identify the
	          // keypad button from the Button's tag
	          Keypad keypadButton = (Keypad) btn.getTag();
	          
	          // Process keypad button
	          ProcessKeypadInput(keypadButton);
	        }
	    });

        // Set adapter of the keypad grid
        mKeyGrid.setAdapter(mKeypadAdapter);
        
        
        
        mKeyGrid.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView <?> parent, View v,int position, long id) {
				// This will not help us catch button clicks!				
			}
        });
    } 

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_calculator, menu);
        return true;
    }
    
    private void ProcessKeypadInput(Keypad keypadButton) {
		// Toast.makeText(this, keypadButton.getText(),
		// Toast.LENGTH_SHORT).show();
		String text = keypadButton.getText().toString();
		String currentInput = userInputText.getText().toString();

		int currentInputLen = currentInput.length();
		String evalResult = null;
		//double userInputValue = Double.NaN;

		switch (keypadButton) {
		case BACKSPACE: // Handle backspace
			// If has operand skip backspace
			if (resetInput)
				return;

			int endIndex = currentInputLen - 1;

			// There is one character at input so reset input to 0
			if (endIndex < 1) {
				userInputText.setText("0");
			}
			// Trim last character of the input text
			else {
				userInputText.setText(currentInput.subSequence(0, endIndex));
			}
			break;
			
		case DOT: // Handle decimal point
			if (pointInput)
			{
				userInputText.append(text);
				pointInput = false;
			}
			break;
			
		case CE: // Handle clear input
			userInputText.setText("0");
			pointInput = true;
			break;

		case C: // Handle clear input and stack
			userInputText.setText("0");
			pointInput = true;
			clearStacks();
			break;

		case DIV:
		case PLUS:
		case MINUS:
		case MULTIPLY:
			if (resetInput) {
				mInputStack.pop();
				mOperationStack.pop();
			} else {
				if (currentInput.charAt(0) == '-') {
					mInputStack.add("(" + currentInput + ")");
				} else {
					mInputStack.add(currentInput);
				}
				mOperationStack.add(currentInput);
			}

			mInputStack.add(text);
			mOperationStack.add(text);

			dumpInputStack();
			evalResult = evaluateResult(false);
			if (evalResult != null)
				userInputText.setText(evalResult);

			resetInput = true;
			break;
			
		case RESULT:
			if (mOperationStack.size() == 0)
				break;

			mOperationStack.add(currentInput);
			evalResult = evaluateResult(true);
			if (evalResult != null) {
				clearStacks();
				userInputText.setText(evalResult);
				resetInput = false;
				hasFinalResult = true;
			}
			break;

		default:
			if (currentInput.equals("0") || resetInput || hasFinalResult) 
			{
				userInputText.setText(text);					
				hasFinalResult = false;
			}				
			else
			{					
				userInputText.append(text);
			}
			resetInput = false;
						
			break;

		}

	}

	private void clearStacks() {
		mInputStack.clear();
		mOperationStack.clear();
	}

	private void dumpInputStack() {
		Iterator <String> it = mInputStack.iterator();
		StringBuilder sb = new StringBuilder();

		while (it.hasNext()) {
			CharSequence iValue = it.next();
			sb.append(iValue);

		}

	}

	private String evaluateResult(boolean requestedByUser) {
		if ((!requestedByUser && mOperationStack.size() != 4)
				|| (requestedByUser && mOperationStack.size() != 3))
			return null;

		String left = mOperationStack.get(0);
		String operator = mOperationStack.get(1);
		String right = mOperationStack.get(2);
		String tmp = null;
		if (!requestedByUser)
			tmp = mOperationStack.get(3);

		double leftVal = Double.parseDouble(left.toString());
		double rightVal = Double.parseDouble(right.toString());
		double result = Double.NaN;

		if (operator.equals(Keypad.DIV.getText())) {
			result = leftVal / rightVal;
		} else if (operator.equals(Keypad.MULTIPLY.getText())) {
			result = leftVal * rightVal;

		} else if (operator.equals(Keypad.PLUS.getText())) {
			result = leftVal + rightVal;
		} else if (operator.equals(Keypad.MINUS.getText())) {
			result = leftVal - rightVal;

		}

		String resultStr = doubleToString(result);
		if (resultStr == null)
			return null;

		mOperationStack.clear();
		if (!requestedByUser) {
			mOperationStack.add(resultStr);
			mOperationStack.add(tmp);
		}

		return resultStr;
	}

	private String doubleToString(double value) {
		if (Double.isNaN(value))
			return null;

		long longVal = (long) value;
		if (longVal == value)
			return Long.toString(longVal);
		else
			return Double.toString(value);

	}

/*	private double tryParseUserInput() {
		String inputStr = userInputText.getText().toString();
		double result = Double.NaN;
		try {
			result = Double.parseDouble(inputStr);

		} catch (NumberFormatException nfe) {}
		return result;

	}
	*/

}
